package com.qingmeng.outsourcing.portal.service.impl;

import com.aliyuncs.exceptions.ClientException;
import com.qingmeng.outsourcing.mapper.BalanceMapper;
import com.qingmeng.outsourcing.mapper.CheckCodeMapper;
import com.qingmeng.outsourcing.mapper.UserMapper;
import com.qingmeng.outsourcing.model.*;
import com.qingmeng.outsourcing.portal.enums.RegisterResult;
import com.qingmeng.outsourcing.portal.enums.SMSResult;
import com.qingmeng.outsourcing.portal.enums.SMSType;
import com.qingmeng.outsourcing.portal.model.dto.UserRegisterParam;
import com.qingmeng.outsourcing.portal.service.UserService;
import com.qingmeng.outsourcing.portal.util.SecurityUtils;
import com.qingmeng.outsourcing.portal.util.ShortMessageUtil;
import com.qingmeng.outsourcing.security.util.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl implements UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CheckCodeMapper checkCodeMapper;

    @Autowired
    private BalanceMapper balanceMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    public User getUserByUsername(String username) {
        UserExample example = new UserExample();
        example.createCriteria().andUserNameEqualTo(username);
        List<User> users = userMapper.selectByExample(example);

        if (!CollectionUtils.isEmpty(users)){
            return users.get(0);
        }
        return null;
    }

    @Override
    public SMSResult sendMessageCode(String phone, Integer identify) {
        //首先验证电话号码是否合规
        if(phone == null || phone.length() != 11){
            return SMSResult.PHONE_ERROR;
        }
        //不是修改手机号和忘记密码的时候执行的分支（也就是注册雇主和开发者时候执行的分支）
        if(identify != SMSType.MODIFY_PHONE.getCode() && identify != SMSType.FORGET_PASSWORD.getCode()){
            UserExample example = new UserExample();
            //and phone = 123 and is_published = 2
            example.createCriteria().andPhoneEqualTo(phone).andIsPublisherEqualTo(identify);
            if(userMapper.countByExample(example)>0){
                return SMSResult.PHONE_ALREADY_REGISTERED;
            }
        }else if(identify == SMSType.MODIFY_PHONE.getCode()){
            //当前登录的用户
            User currentUser = SecurityUtils.getCurrentUser();
            if(currentUser == null){
                return SMSResult.NO_LOGIN_NO_MODIFY_PHONE;
            }
            UserExample example = new UserExample();
            example.createCriteria().andPhoneEqualTo(phone);
            List<User> users = userMapper.selectByExample(example);
            if(!CollectionUtils.isEmpty(users)){
                for(User user: users){
                    if(currentUser.getIsPublisher().equals(user.getIsPublisher())){
                        return SMSResult.PHONE_ALREADY_REGISTERED;
                    }
                }
            }
        }

        String random = ShortMessageUtil.createRandomNum(6);

        CheckCode checkCode = new CheckCode();
        checkCode.setPhone(phone);
        checkCode.setCode(random);

        if(checkCodeMapper.insertSelective(checkCode) > 0){
            try{
                //调用工具类发送验证码
                String ret = ShortMessageUtil.sendMsg(phone,"青盟科技","SMS_174891011",random);
                if("网络问题，请重试".equals(ret)){
                    return SMSResult.NETWORK_ERROR;
                }else if ("生成验证码失败".equals(ret)){
                    return SMSResult.SEND_SMS_FAILED;
                }
            } catch (ClientException e){
                logger.error("发送短信出现异常，异常信息为：{}",e.toString());
                return SMSResult.NETWORK_ERROR;
            }
        }

        return SMSResult.SEND_SMS_SUCCESS;
    }

    /**
     * 检查前端发送过来的手机号和验证码
     * @param phone 前端发送过来的手机号
     * @param code 前端发过来的验证码
     * @return 验证成功返回true，失败返回false
     */
    private boolean verifyAuthCode(String phone, String code){
        if(StringUtils.isEmpty(code) || StringUtils.isEmpty(phone)){
        return false;
        }
        CheckCodeExample example = new CheckCodeExample();
        example.createCriteria().andPhoneEqualTo(phone).andCodeEqualTo(code);
        return checkCodeMapper.countByExample(example) > 0;
    }

    @Override
    public RegisterResult register(UserRegisterParam param) {
        //第一步，先检查验证码
        if(!verifyAuthCode(param.getPhone(),param.getCode())){
            return RegisterResult.AUTH_CODE_ERROR;
        }

        //第二步，检查用户名是否重复
        UserExample userExample = new UserExample();
        userExample.createCriteria().andUserNameEqualTo(param.getUsername());
        if(userMapper.countByExample(userExample) > 0){
            return RegisterResult.USERNAME_EXIST;
        }

        //判断手机号是否注册过当前身份
        UserExample phoneExample = new UserExample();
        phoneExample.createCriteria().andPhoneEqualTo(param.getPhone())
                .andIsPublisherEqualTo(param.getIdentity());
        if (userMapper.countByExample(phoneExample) > 0){
            return RegisterResult.REG_DUPLICATED;
        }

        //将用户信息插入User表
        User user = new User();
        user.setUserName(param.getUsername());
        user.setIsPublisher(param.getIdentity());
        user.setPassword(passwordEncoder.encode(param.getPassword()));
        if(userMapper.insertSelective(user) > 0){
            //插入user表成功之后，创建一个默认的账户信息，并插入到余额表
            Balance balance = new Balance();
            balance.setUserId(user.getId());
            balance.setBalance(new BigDecimal("0.00"));
            if(balanceMapper.insertSelective(balance) > 0){
                return RegisterResult.REG_SUCCESS;
            }
        }
        return RegisterResult.REG_FAILDE;
    }

    @Override
    public Map<String, String> login(String username, String password) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,password);
        Authentication authentication = null;
        try {
            authentication = authenticationManager.authenticate(token);
        }catch (AuthenticationException e){
            logger.error("用户名和密码错误" + e);
            return null;
        }
        //将 authentication 存入安全框架
//        SecurityContextHolder.getContext().setAuthentication(authentication);

        Map<String,String> tokenMap = new HashMap<>();
        if(authentication != null){
            //从验证结果返回的 authentication 中获取 UserDetails 对象
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            //根据UserDetails对象生成token字符串
            String tokenString = jwtTokenUtil.generateToken(userDetails);
            tokenMap.put("token",tokenString);
            tokenMap.put("tokenHead",jwtTokenUtil.getTokenHead());
            tokenMap.put("tokenHeader",jwtTokenUtil.getTokenHeader());
        }
        return tokenMap;
    }
}
